package com.zhu.classfile.attribute;

import com.zhu.classfile.constant.ConstantPool;

import java.nio.ByteBuffer;

/**
 * LocalVariableTable 属性
 * 用于记录局部变量的名称、类型、作用域和槽位
 *
 * 结构：
 * LocalVariableTable_attribute {
 *     u2 attribute_name_index;
 *     u4 attribute_length;
 *     u2 local_variable_table_length;
 *     {   u2 start_pc;
 *         u2 length;
 *         u2 name_index;
 *         u2 descriptor_index;
 *         u2 index;
 *     } local_variable_table[local_variable_table_length];
 * }
 */
public class LocalVariableTableAttribute implements AttributeInfo {

    private LocalVariableTableEntry[] localVariableTable;

    @Override
    public void readInfo(ByteBuffer reader) {
        int tableLength =Short.toUnsignedInt(reader.getShort());
        localVariableTable = new LocalVariableTableEntry[tableLength];
        for (int i = 0; i < tableLength; i++) {
            localVariableTable[i] = new LocalVariableTableEntry(
                    Short.toUnsignedInt(reader.getShort()), // start_pc
                    Short.toUnsignedInt(reader.getShort()), // length
                    Short.toUnsignedInt(reader.getShort()), // name_index
                    Short.toUnsignedInt(reader.getShort()), // descriptor_index
                    Short.toUnsignedInt(reader.getShort())  // index
            );
        }
    }

    /**
     * 根据字节码偏移（pc）和局部变量槽位（index），查找变量名
     *
     * @param pc    当前程序计数器
     * @param index 局部变量槽位
     * @return 变量名，未找到返回 null
     */
    public String getVariableName(int pc, int index, ConstantPool cp) {
        for (LocalVariableTableEntry entry : localVariableTable) {
            if (entry.getIndex() == index &&
                    pc >= entry.getStartPc() &&
                    pc < entry.getStartPc() + entry.getLength()) {
                return cp.getUtf8(entry.getNameIndex());
            }
        }
        return null;
    }

    /**
     * 根据槽位和 pc 获取变量类型描述符
     */
    public String getDescriptor(int pc, int index, ConstantPool cp) {
        for (LocalVariableTableEntry entry : localVariableTable) {
            if (entry.getIndex() == index &&
                    pc >= entry.getStartPc() &&
                    pc < entry.getStartPc() + entry.getLength()) {
                return cp.getUtf8(entry.getDescriptorIndex());
            }
        }
        return null;
    }

    // ------------------------
    // 内部静态类：不可变数据结构
    // ------------------------

    public static class LocalVariableTableEntry {
        private final int startPc;
        private final int length;
        private final int nameIndex;
        private final int descriptorIndex;
        private final int index;

        public LocalVariableTableEntry(int startPc, int length, int nameIndex,
                                       int descriptorIndex, int index) {
            this.startPc = startPc;
            this.length = length;
            this.nameIndex = nameIndex;
            this.descriptorIndex = descriptorIndex;
            this.index = index;
        }

        public int getStartPc() { return startPc; }
        public int getLength() { return length; }
        public int getNameIndex() { return nameIndex; }
        public int getDescriptorIndex() { return descriptorIndex; }
        public int getIndex() { return index; }

        @Override
        public String toString() {
            return String.format("LocalVarEntry[startPc=%d, length=%d, nameIdx=%d, descIdx=%d, index=%d]",
                    startPc, length, nameIndex, descriptorIndex, index);
        }
    }
}